package com.flutter.flutter_blue_card_plugin;

import androidx.annotation.NonNull;
import android.content.Context;
import android.os.Handler;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
import com.excelsecu.driver.util.BytesUtil;
import com.excelsecu.transmit.EsDevice;
import com.excelsecu.transmit.EsDeviceDescriptor;
import com.excelsecu.transmit.EsDeviceInfo;
import com.excelsecu.transmit.EsDeviceManager;
import com.excelsecu.transmit.EsDeviceScanner;
import com.excelsecu.transmit.EsDeviceScanner.EsBluetoothScanListener;
import com.excelsecu.transmit.EsDevice.OnStateChangeListener;
import com.excelsecu.transmit.util.LogUtil;
import java.util.LinkedHashMap;
import java.util.Map;



/** FlutterBlueCardPlugin */
public class FlutterBlueCardPlugin implements FlutterPlugin, MethodCallHandler {
  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity
  private MethodChannel channel;
  private EsDeviceScanner esDeviceScanner;
  private EsDevice esDevice;
  private Context context;

  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    context = flutterPluginBinding.getApplicationContext();
    channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "flutter_blue_card_plugin");
    channel.setMethodCallHandler(this);
    esDeviceScanner = EsDeviceScanner.createScanner(context);
  }

  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    if (call.method.equals("getPlatformVersion")) {
      result.success("Android " + android.os.Build.VERSION.RELEASE);
    }
    else if (call.method.equals("connect")) {
      connect(call,result);
    }
    else if (call.method.equals("disconnect")) {
      disconnect(call,result);
    }
    else if (call.method.equals("sendData")) {
      sendData(call,result);
    }
    else {
      result.notImplemented();
    }
  }

  private void connect(MethodCall call, MethodChannel.Result result) {
    final String sn = call.argument("sn");
    LogUtil.i("Demo", "connect: "+ sn);
    final MethodChannel.Result callResult = result;
    esDeviceScanner.setScanListener(
            new EsBluetoothScanListener(){
              boolean _scanEnd = false;
              @Override
              public void onScanStart(EsDeviceScanner scanner) {
              }

              @Override
              public void onScanStop(EsDeviceScanner scanner) {
                if (!_scanEnd) {
                  esDeviceScanner.setScanListener(null);
                  esDeviceScanner.stopScan();
                  Map<String, Object> info = new LinkedHashMap<String, Object>();
                  info.put("sn", sn);
                  info.put("code",1);
                  info.put("desc","未找到设备");
                  callResult.success(info);
                }
              }

              @Override
              public void onBluetoothStateChange(EsDeviceScanner scanner, int bluetoothState) {
                LogUtil.i("Demo", "onBluetoothStateChange: "+bluetoothState);
                if (bluetoothState == EsDeviceScanner.STATE_ON) {
                  esDeviceScanner.startScan(30 * 1000);
                }
              }

              @Override
              public void onDeviceFound(EsDeviceScanner scanner, EsDeviceInfo bluetoothDeviceInfo) {
                LogUtil.i("Demo", "onDeviceFound: "+bluetoothDeviceInfo.getName());

                if (sn.equals(bluetoothDeviceInfo.getName())){
                  LogUtil.i("Demo", "find device: "+ sn);
                  _scanEnd = true;
                  EsDeviceDescriptor descriptor = new EsDeviceDescriptor(EsDevice.TYPE_BLUETOOTH, bluetoothDeviceInfo);
                  EsDevice device = EsDeviceManager.getInstance(context).createDevice(descriptor);
                  int deviceId = device.getId();

                  esDevice = EsDeviceManager.getInstance(context).getDevice(deviceId);
                  if (esDevice == null) {
                    Map<String, Object> info = new LinkedHashMap<String, Object>();
                    info.put("sn", sn);
                    info.put("code",1);
                    info.put("desc","连接失败");
                    callResult.success(info);
                    return;
                  }
                  esDevice.addStateListener(new OnStateChangeListener(){
                    @Override
                    public void onStateChange(int state, EsDevice esDevice) {
                      switch (state) {
                        case EsDevice.STATE_CONNECTED:
                          Map<String, Object> info = new LinkedHashMap<String, Object>();
                          info.put("sn", sn);
                          info.put("code",0);
                          info.put("desc","已连接");
                          callResult.success(info);
                          break;
                        default:
                          break;
                      }
                    }
                  });
                  esDevice.connectAsync();

                  esDeviceScanner.setScanListener(null);
                  esDeviceScanner.stopScan();
                }
              }

              @Override
              public void onScanTimeout(EsDeviceScanner arg0) {

              }
            }
    );
    esDeviceScanner.enableBluetooth();
    esDeviceScanner.startScan(30 * 1000);
  }

  private void disconnect(MethodCall call, MethodChannel.Result result) {
    final MethodChannel.Result callResult = result;
    final Handler handler = new Handler();
    new Thread(new Runnable() {
      @Override
      public void run() {
        if (esDevice != null) {
          esDevice.disconnect();
          handler.post(new Runnable() {
            @Override
            public void run() {
              Map<String, Object> info = new LinkedHashMap<String, Object>();
              info.put("code",0);
              info.put("desc","已断开连接");
              callResult.success(info);
            }
          });
        }
      }
    }).start();
  }


  private void sendData(MethodCall call, MethodChannel.Result result) {
    final String cmdStr = call.argument("data");
    final byte[] hexBytes = BytesUtil.hexStringToBytes(cmdStr);
    final MethodChannel.Result callResult = result;
    final Handler handler = new Handler();
    new Thread(new Runnable() {

      @Override
      public void run() {
        byte[] recvBuffer = new byte[1024];
        int[]  recvBufferLen = new int[]{recvBuffer.length};
        int nRet = esDevice.sendApdu(hexBytes, hexBytes.length, recvBuffer, recvBufferLen);
        final String recvStr = BytesUtil.bytesToHexString(recvBuffer, 0, recvBufferLen[0]);
        final int resCode = nRet;
        LogUtil.i("Demo", "ret: "+nRet+", recv data: "+recvStr);

        if (0 == resCode) {
          handler.post(new Runnable() {
            @Override
            public void run() {
              Map<String, Object> info = new LinkedHashMap<String, Object>();
              info.put("code",0);
              info.put("data",recvStr);
              callResult.success(info);
            }
          });
        }else {
          handler.post(new Runnable() {
            @Override
            public void run() {
              Map<String, Object> info = new LinkedHashMap<String, Object>();
              info.put("code",resCode);
              info.put("desc","发送失败");
              callResult.success(info);
            }
          });
        }
      }
    }).start();
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
  }
}
